﻿#define UniTest
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace UpgradeLoader
{
    /// <summary>
    /// 只下载一个压缩包进行全量更新
    /// </summary>
    public class OneFileUpgradeManager
    {

        public SoftwareUpdate LocalUpdate;

        public OneFileDownCenter DownCenter;

        private ServerUpgradeInfo serverUpdate;
        private string OkFileName = "downUpgarde.json";

        private string backupDir = ".old\\";
        private string upgradeDir = ".new\\";
        string upfileName = "UpgradeSettings.xml";
        string serverfileName = "Server_UpgradeSettings.xml";
        string currentDir = string.Empty;

        public event Action<bool> UpgradeFinishEvent;

        public OneFileUpgradeManager()
        {
            currentDir = AppContext.BaseDirectory;
            serverUpdate = new ServerUpgradeInfo()
            {
                IsForceUpgrade = false,
                CurrentVersion = "1.0.0.8",
                SaveDir = Path.Combine(currentDir, upgradeDir),
                UpgradeZipFile = "http://127.0.0.1:5769/upgradedir/upgradedir.zip",
                MD5 = string.Empty,
            };
#if UniTest
            currentDir = @"D:\Code\repo\upgrade\UpgradeLoader\bin\Debug\net6.0-windows\";
            serverUpdate.MD5 = Util.GetMD5HashFromFile(@"d:\iisweb\mainUpgrade\upgradedir\upgradedir.zip");
#endif
            var fN = currentDir + upfileName;
            if (!File.Exists(fN))
            {
                throw new Exception("升级配置文件不存在");
            }
            LocalUpdate = Util.DeserializeXml<SoftwareUpdate>(fN);
            var saveDir = Path.Combine(currentDir, upgradeDir);
            if (DownCenter == null)
            {
                DownCenter = new OneFileDownCenter(serverUpdate);
                DownCenter.DownloadFinishEventAsync += DownloadFinished;
            }
        }

        public async Task StartUpgrade()
        {
            if (LocalUpdate == null || serverUpdate == null)
            {
                throw new Exception("未获取到升级配置");
            }
            if (LocalUpdate.VersionInfo.CurrentVersionNum >= serverUpdate.CurrentVersionNum)
            {
                Environment.Exit(0);
                return;
            }

            if (File.Exists(OkFileName))
            {
                var downOkFile = Path.Combine(currentDir, OkFileName);
                var downFile = Util.ToObj<DowningFile>(downOkFile);
                if (downFile != null && downFile.isCanUpgrade && downFile.Version > LocalUpdate.VersionInfo.CurrentVersionNum && downFile.Items.Count > 0)
                {

                    var isUpdate = DoFinish(downFile.Items[0]);
                    if (isUpdate)
                    {
                        File.Delete(OkFileName);
                    }
                }
                return;
            }

            this.StartDownload();
        }

        /// <summary>
        /// 从升级服务器下载升级配置文件
        /// </summary>
        /// <returns></returns>


        public void StartDownload()
        {
           
            DownCenter.StartDownload();
        }

        private async void DownloadFinished(DownloadItem item)
        {
            if (DownCenter == null) return;
            try
            {
                var isok = DownCenter.CheckSumFile(item);

                if (item.IsDownSuccess == false)
                {

                    DownCenter.RetryDownload();

                }
                else
                {
                    DoFinish(item);
                }

            }
            catch (Exception ex)
            {
                throw;
            }
        }

        private bool DoFinish(DownloadItem oneItem)
        {
            if (serverUpdate == null) throw new Exception("远程更新配置文件缺失");
            bool isUpgraded = false;
            if (serverUpdate.IsForceUpgrade == true)
            {
                ForceUpdate(oneItem);
                isUpgraded = true;
            }
            else
            {
                var result = MessageBox.Show("是否结束当前运行软件，进行升级", "升级提示", MessageBoxButtons.YesNo);
                if (result == DialogResult.Yes)
                {
                    ForceUpdate(oneItem);
                    isUpgraded = true;
                }
                else
                {
                    cancelUpdate(oneItem);
                    isUpgraded = false;
                }
            }
            UpgradeFinishEvent?.Invoke(isUpgraded);
            return isUpgraded;
        }

        private void cancelUpdate(DownloadItem item)
        {
            DowningFile downFile = new DowningFile()
            {
                isCanUpgrade = true,
                Items = new List<DownloadItem>() { item },
                Version = serverUpdate.CurrentVersionNum
            };
            var str = Util.ToJson(downFile);
            File.WriteAllText(OkFileName, str);
        }

        private void ForceUpdate(DownloadItem fullZip)
        {
            if (fullZip.IsZip == false) return;
            ShutdownProcess();
            var fileZip = Path.Combine(fullZip.LocalDir, fullZip.DestFileName);
            var dir = Path.Combine(currentDir, upgradeDir);
            Util.DeCompressionFile(fileZip, dir);
            File.Delete(fileZip);
            var dirInfo = new DirectoryInfo(dir);
            dirInfo.EnumerateDirectories().ToList().ForEach(item =>
            {
                var itemdir = Path.Combine(item.Parent!.Parent!.FullName, item.Name);
                if (Directory.Exists(itemdir))
                {
                    Directory.Delete(itemdir, true);
                }
                item.MoveTo(itemdir);
            });
            dirInfo.EnumerateFiles().ToList().ForEach(f =>
            {
                f.CopyTo(Path.Combine(currentDir, f.Name), true);
            });


            dirInfo.Delete(true);
            UpdateUpdateSettings();
            StartProcess();
            var dirOld = new DirectoryInfo(".old");
            if (dirOld.Exists)
            {
                dirOld.Delete(true);
            }
        }

        private void UpdateUpdateSettings()
        {
            this.LocalUpdate.VersionInfo.CurrentVersion = this.serverUpdate.CurrentVersion;
            Util.SerializeXml(this.LocalUpdate, Path.Combine(currentDir, upfileName));
        }
        private void ShutdownProcess()
        {
            if (LocalUpdate == null) throw new Exception("未找到本地升级配置项");
            if (string.IsNullOrWhiteSpace(LocalUpdate.ApplicationPath))
            {
                throw new Exception("未找到本地软件路径");
            }
            var process = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(LocalUpdate.ApplicationPath));
            if (process.Length > 0)
            {
                process[0].Kill();
            }
            Thread.Sleep(2000);
        }
        private void StartProcess()
        {
            Process.Start(LocalUpdate.ApplicationPath);
        }



        public static SoftwareUpdate CreateTestInstalledSetting()
        {
            SoftwareUpdate update = new();
            update.Logging = new Logging() { ErrorHandling = "Rollback", LogPath = "upgrade.log" };
            update.UpdateServer = new UpdateServer() { PrimaryServerURL = "http://127.0.0.1:5769/upgradedir/", FallbackServerURL = "http://127.0.0.1:5770/upgradedir/" };
            update.VersionInfo = new VersionInfo() { CurrentVersion = "1.0.0.0" };
            update.UpdatePolicy = 1;

            update.ApplicationPath = @"D:\Code\repo\upgrade\UpgradeLoader\bin\Debug\net6.0-windows\TestUpgradeSoftware\MyMeeting.exe";
            return update;
        }

        public SoftwareUpdate CreateUpdatePackages(SoftwareUpdate update, string upitemsDir)
        {
            if (update == null) return null;
            if (!Directory.Exists(upitemsDir)) return null;
            update.UpdatePackages = new UpdatePackages();
            update.UpdatePackages.UpdateItems = Util.GetUpdateList(upitemsDir);
            return update;
        }

        public void BackupOldSoftware()
        {
            //var softwarePath = Path.Combine(currentDir, softwareDir);
            //string backFolder = Path.Combine(currentDir,backupDir);
            //var backdir = new DirectoryInfo(backupDir);
            //Util.CopyChildFolderFile(softwarePath, backFolder, true, backdir.Name);
        }

        public List<UpdateItem> DownloadFile(List<UpdateItem> updateItems, string server, string localDir)
        {
            if (updateItems == null || updateItems.Count == 0) return null;
            List<UpdateItem> Downloading = new List<UpdateItem>();
            List<UpdateItem> Finish = new List<UpdateItem>();
            while (updateItems.Count > 0 || Downloading.Count > 0)
            {
                if (Downloading.Count < 5)
                {
                    var item = updateItems[0];
                    updateItems.RemoveAt(0);
                    Util.DownloadFileAsync(server, item, localDir);
                }
                else
                {
                    Thread.Sleep(1500);
                    var finish = Downloading.Where(a => a.IsFinish).ToList();
                    Finish.AddRange(finish);
                    foreach (var item in finish)
                    {
                        Downloading.Remove(item);
                    }
                }
            }
            return Finish;

        }
     
        public async Task DownServerUpdateFile()
        {
            var server = LocalUpdate.UpdateServer.PrimaryServerURL.ToLower().Replace("upgradedir/", "");
            if (!server.StartsWith("http"))
            {
                return;
            }
            var serverFile = server + upfileName;
            var saveServerFileDir = Path.Combine(currentDir, upgradeDir);
            Util.CreateFolder(saveServerFileDir);
            var saveServerFileName = Path.Combine(saveServerFileDir, serverfileName);
            await Util.DownloadFileAsync(serverFile, saveServerFileName);

            //if(File.Exists(saveServerFileName))
            //{
            //    serverUpdate = Util.DeserializeXml<SoftwareUpdate>(saveServerFileName);
            //}

        }
    }
}
